package com.peng.rpc.socket.client;

import com.peng.rpc.entity.RpcResponse;
import com.peng.rpc.enumeration.ResponseCode;
import com.peng.rpc.enumeration.RpcError;
import com.peng.rpc.exception.RpcException;
import com.peng.rpc.loadBalance.LoadBalance;
import com.peng.rpc.loadBalance.RandomLoadBalance;
import com.peng.rpc.registry.NacosServiceDiscovery;
import com.peng.rpc.registry.ServiceDiscovery;
import com.peng.rpc.socket.util.ObjectReader;
import com.peng.rpc.socket.util.ObjectWriter;
import com.peng.rpc.serializer.CommonSerializer;
import com.peng.rpc.common.client.RpcClient;
import com.peng.rpc.entity.RpcRequest;
import com.peng.rpc.util.ResponseChecker;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * 利用socket来读写协议包的类
 * @author Wonderson
 * @email wpp.ds@foxmail.com
 * @date 2022/2/27 19:20
 */
@Slf4j
public class SocketRpcClient implements RpcClient {

    private CommonSerializer serializer;
    private ServiceDiscovery serviceDiscovery;

    public SocketRpcClient(int serializerCode, LoadBalance loadBalance) {
        this.serializer = CommonSerializer.getSerializerByCode(serializerCode);
        this.serviceDiscovery = new NacosServiceDiscovery(loadBalance);
    }

    public SocketRpcClient() {
        this(DEFAULT_SERIALIZER, new RandomLoadBalance());
    }

    public SocketRpcClient(int serializerCode) {
        this(serializerCode, new RandomLoadBalance());
    }

    public SocketRpcClient(LoadBalance loadBalance) {
        this(DEFAULT_SERIALIZER, loadBalance);
    }

    @Override
    public Object sendRequest(RpcRequest rpcRequest) {
        if (serializer == null) {
            log.error("未设置序列化器，无法发送请求");
            throw new RpcException(RpcError.SERIALIZER_UNSETTED);
        }
        InetSocketAddress inetSocketAddress = serviceDiscovery.lookupService(rpcRequest.getInterfaceName());
        try (Socket socket = new Socket()) {
            socket.connect(inetSocketAddress);
            OutputStream os = socket.getOutputStream();
            InputStream is = socket.getInputStream();
            ObjectWriter.writeObject(os, rpcRequest, serializer);
            RpcResponse rpcResponse = (RpcResponse) ObjectReader.readObject(is);
            ResponseChecker.check(rpcRequest, rpcResponse);
            return rpcResponse;
        } catch (IOException e) {
            log.info("发送远程请求失败：{}", e.getMessage());
            throw new RpcException(RpcError.SOCKET_REQUEST_FAILED);
        }
    }

}
